/*
 * x86_64/msrs.hh - MSRs wrappers.
 * Copyright (C) 2007  Mikhail Vorozhtsov
 * See the LICENSE section of the README file for details.
 */

/* $Id$ */

#ifndef HEADER_X86_64_MSRS_HH
#define HEADER_X86_64_MSRS_HH

#include HEADER (utils,setters.hh)

START_NAMESPACE (x86_64)

const u32_t MSR_APIC_BASE = 0x0000001B;
const u32_t MSR_EFER = 0xC0000080;
const u32_t MSR_STAR = 0xC0000081;
const u32_t MSR_LSTAR = 0xC0000082;
const u32_t MSR_SF_MASK = 0xC0000084;
const u32_t MSR_FS_BASE = 0xC0000100;
const u32_t MSR_GS_BASE = 0xC0000101;

INLINE
static u64_t
get_msr (u32_t reg)
{
  u32_t eax, edx;
  asm volatile (
    "rdmsr\n"
    : "=a"(eax), "=d"(edx)
    : "c"(reg)
  );
  return ((u64_t) edx << 32) | (u64_t) eax;
}

INLINE
static void
set_msr (u32_t reg, u64_t value)
{
  asm volatile (
    "wrmsr\n"
    :
    : "a"((u32_t) value), "d"((u32_t) (value >> 32)), "c"(reg)
  );
}

#define __X86_64_MSR_GETTER_SETTER(name,msr) \
  UTILS_RAW_ZERO (name ## _t, u64_t) \
  \
  INLINE \
  static name ## _t \
  get () \
  { \
    name ## _t result; \
    result.raw = get_msr (msr); \
    return result; \
  } \
  \
  INLINE \
  void \
  set () \
  { \
    set_msr (msr, raw); \
  }

union apic_base_t
{
  struct
    {
      u64_t : 8;
      u64_t BSP : 1;
      u64_t : 2;
      u64_t E : 1;
      u64_t base : 52;
    };
  u64_t raw;

  __X86_64_MSR_GETTER_SETTER (apic_base, MSR_APIC_BASE)

  UTILS_BOOL_SETTER (apic_base_t, BSP)
  UTILS_BOOL_SETTER (apic_base_t, E)

  INLINE
  u64_t
  get_ptr () const
  {
    return base << 12;
  }

  INLINE
  apic_base_t &
  set_ptr (u64_t addr)
  {
    base = addr >> 12;
    return *this;
  }
};

union efer_t
{
  struct
    {
      u64_t SCE : 1;
      u64_t : 7;
      u64_t LME : 1;
      u64_t : 1;
      u64_t LMA : 1;
      u64_t NXE : 1;
      u64_t : 2;
      u64_t FFXSR : 1;
      u64_t : 49;
    };
  u64_t raw;

  __X86_64_MSR_GETTER_SETTER (efer, MSR_EFER)

  UTILS_BOOL_SETTER (efer_t, SCE)
  UTILS_BOOL_SETTER (efer_t, LME)
  UTILS_BOOL_SETTER (efer_t, LMA)
  UTILS_BOOL_SETTER (efer_t, NXE)
  UTILS_BOOL_SETTER (efer_t, FFXSR)
};

union star_t
{
  struct
    {
      u64_t EIP : 32;
      u64_t syscall_cs : 16;
      u64_t sysret_cs : 16;
    };
  u64_t raw;

  __X86_64_MSR_GETTER_SETTER (star, MSR_STAR)

  UTILS_SETTER (star_t, u64_t, EIP)
  UTILS_SETTER (star_t, u64_t, syscall_cs)
  UTILS_SETTER (star_t, u64_t, sysret_cs)
};

#undef __X86_64_MSR_GETTER_SETTER

END_NAMESPACE

#endif /* HEADER_X86_64_MSRS_HH */

